/** Copyright Notice:

    Copyright (C) 2011 Ivo Wingelaar

    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
    arising from the use of this software.

    Permission is granted to anyone to use this software for any purpose,
    including commercial applications, and to alter it and redistribute it
    freely, subject to the following restrictions:

    1.  The origin of this software must not be misrepresented; you must not
        claim that you wrote the original software. If you use this software
        in a product, an acknowledgment in the product documentation would be
        appreciated but is not required.
    2.  Altered source versions must be plainly marked as such, and must not be
        misrepresented as being the original software.
    3.  This notice may not be removed or altered from any source distribution.

    Please note that the Myth Library is based in part on the work of Nikolaus
    Gebhardt (Irrlicht Engine) and I give full credits to him, and the people who
    helped him for making available an excellent piece of code.

**/

//
// MythCryptoReadStreamEncrypted_C.cpp 010: implementation of the encrypted readstream
//

#include "MythCrypto_InputEncrypted_C.hpp"

namespace Myth
{
namespace Crypto
{

/** constructor **/
/// \param   StreamCipher *cipher
///         A pointer to the streamcipher you want to use to encrypt this stream.
/// \param   Stream::Input *already_opened_stream
///         A pointer to an already opened stream.
/// \param   uint8_t *password
///         A pointer to a password.
/// \param   uint32_t password_len
///         The length of the password.
/// \param   const std::string& stream_name
///         The name you want to give this stream.
ReadStreamEncrypted_C::ReadStreamEncrypted_C( StreamCipher *cipher,
                                              Stream::Input *already_opened_stream,
                                              uint8_t *password,
                                              uint32_t password_len,
                                              const std::string& stream_name) :
    Stream::Input(stream_name),
    mCipher(cipher),
    mStream(already_opened_stream),
    mPassword(password),
    mPasswordLength(password_len)
{
    mCipher->init(mPassword, mPasswordLength);

    mStream->increment_counter();
}

/** destructor **/
ReadStreamEncrypted_C::~ReadStreamEncrypted_C()
{
    mStream->decrement_counter();
}

/** virtual function **/
/** read             **/
//! Reads an amount of bytes from the stream.
/// \return int32_t
///         The number of bytes read.
/// \param   void* buffer
///         The buffer you want the read bytes to be placed.
/// \param   uint32_t size
///         The number of bytes you want to read.
int32_t ReadStreamEncrypted_C::read( void *buffer,
                                 uint32_t size)
{
    uint8_t *buffer2 = new uint8_t[size];

    int32_t ret = mStream->read(buffer2, size);

    mCipher->transform(buffer2, (uint8_t*)buffer, ret);

    return ret;
}

/** virtual function **/
/** seek             **/
//! If possible, changes position in the stream.
/// \return bool
///         True if the new position was reached, false if not supported or an error occured.
/// \param   uint32_t pos
///         The position to change to.
/// \param   bool relative
///         True if the change should be relative to the current pos, false otherwise.
bool ReadStreamEncrypted_C::seek( uint32_t pos,
                                  bool relative)
{
    if(!mStream->seek(pos, relative))
        return false;

    mCipher->init(mPassword, mPasswordLength);
    mCipher->skip(mStream->get_pos());

    return true;
}

/** const virtual function **/
/** is_seek_available      **/
//! Returns if seek is available in this stream.
/// \return bool
///         True if seek is implemented, false otherwise.
/// \param  void
bool ReadStreamEncrypted_C::is_seek_available(void) const
{
    return true;
}

/** const virtual function **/
/** get_size               **/
//! If possible, get size of the stream.
/// \return uintptr_t
///         If implemented, the size of the stream, 0 otherwise.
/// \param  void
uintptr_t ReadStreamEncrypted_C::get_size(void) const
{
    return mStream->get_size();
}

/** const virtual function **/
/** is_size_available      **/
//! Returns if get_size is available in this stream.
/// \return bool
///         True if you can get the size, false otherwise.
/// \param  void
bool ReadStreamEncrypted_C::is_size_available(void) const
{
    return true;
}

/** const virtual function **/
/** get_pos                **/
//! If possible, get the current position in the stream.
/// \return uintptr_t
///         The position in the stream if implemented, 0 otherwise.
/// \param  void
uintptr_t ReadStreamEncrypted_C::get_pos(void) const
{
    return mStream->get_pos();
}

/** const virtual function **/
/** is_pos_available       **/
//! Returns if get_pos is available in this stream.
/// \return bool
///         True if you can get the position in the stream, false otherwise.
/// \param  void
bool ReadStreamEncrypted_C::is_pos_available(void) const
{
    return true;
}

} // namespace Crypto
} // namespace Myth
